package queue.model;

import distributions.UniformStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Observer;
import java.util.Queue;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author mostafa
 */
public class InspectionStation extends Observable {

    protected static Timer timer = new Timer();
    public static final long TIME_TRANSLATION_CONST = 1000;

    private static final double badProb = 0.1;

    protected Item currentItem;

    private Queue<Item> queue;
    private UniformStream uniformDis;
    private Random goodOrBadRandom = new Random();
    private String name;

    public InspectionStation(String name, Observer observer) {
        this.name = name;
        this.queue = new LinkedList<Item>();
        currentItem = null;
        this.uniformDis = new UniformStream(0.65, 0.7);
        this.addObserver(observer);
    }


    protected boolean serverAvaiavble() {
        return currentItem == null;
    }

    public void scheduleArrival(Item item) {
        timer.schedule(new ItemArrival(item), item.getArrivateDate());
    }

    protected void serveItem(Item item) {
        System.out.println("Item: " + item + " is being served at " + this.name);
        try {
            // machine is idle
            // start serving now
            currentItem = item;
            ItemDeparture departure = new ItemDeparture(item);
            item.setDeparture(departure);
            // schedule next departure
            timer.schedule(departure, (long) (TIME_TRANSLATION_CONST * uniformDis.getNumber()));
        } catch (IOException ex) {
            Logger.getLogger(InspectionStation.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ArithmeticException ex) {
            Logger.getLogger(InspectionStation.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public String toString() {
        return name;
    }

    public class ItemArrival extends TimerTask {
        private Item item;

        private ItemArrival(Item item) {
            this.item = item;
        }

        @Override
        public void run() {
            if (serverAvaiavble()) { // machine is idle
                // start serving now
                serveItem(item);
            } else {
                System.out.println("Item: " + item + " is queued at "
                        + InspectionStation.this.name + " * q length = " + queue.size());
                queue.add(item);
            }
        }
    }

    public class ItemDeparture extends TimerTask {

        private Item item;

        public ItemDeparture(Item item) {
            this.item = item;
        }

        @Override
        public void run() {
            System.out.println("Item: " + item + " is leaving at "
                        + InspectionStation.this.name + " * q length = " + queue.size());
            boolean isGood = goodOrBadRandom.nextDouble() > badProb;
            item.setGood(isGood);
            setChanged();
            InspectionStation.this.notifyObservers(item);
            if (! queue.isEmpty()) {
                serveItem(queue.poll());
            } else {
                System.out.println("Machine is now idle !");
                currentItem = null;
            }
        }
    }
}
